package com.iwithlong.filter.http;

import com.iwithlong.filter.utils.AgentHttpUtils;
import org.apache.http.Consts;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.InputStreamBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.LaxRedirectStrategy;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Created by liyd on 16/5/10.
 */
public class FineHttpClientHandler implements HttpHandler {

    private static final String ENCODE = "UTF-8";

    private static final int TIME_OUT = 30000;

    private static final int CONNECTION_MAX_TOTAL = 50;

    private static final int CONNECTION_MAX_PER_ROUTE = 20;

    /**
     * 此客户端需要一直存在,所以不关闭
     */
    protected CloseableHttpClient httpClient;

    public FineHttpClientHandler () {
        RequestConfig defaultRequestConfig = RequestConfig.custom().setSocketTimeout(TIME_OUT)
                .setConnectTimeout(TIME_OUT).setConnectionRequestTimeout(TIME_OUT).build();

        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
        connectionManager.setMaxTotal(CONNECTION_MAX_TOTAL);
        connectionManager.setDefaultMaxPerRoute(CONNECTION_MAX_PER_ROUTE);

        this.httpClient = HttpClientBuilder.create().setDefaultRequestConfig(defaultRequestConfig)
                .setConnectionManager(connectionManager).setRedirectStrategy(new LaxRedirectStrategy()).build();
    }

    /**
     * 构建HttpPost
     *
     * @param url         the url
     * @param httpRequest the http request
     * @param requestInfo the request info
     * @return http entity enclosing request base
     */
    protected HttpRequestBase buildHttpRequest(String url, HttpRequestBase httpRequest, RequestInfo requestInfo) {
        try {

            httpRequest.setURI(URI.create(url));

            httpRequest.setHeader("x-forwarded-for_new", requestInfo.getRemoteIP());

            List<Header> headers = new ArrayList<Header>();

            Header header = new BasicHeader("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.94 Safari/537.36");

            headers.add(header);

////            headers.put("Referer", p.url);
//            headers.put("User-Agent", "");
//            headers.put("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
//            headers.put("Accept-Language","zh-cn,zh;q=0.5");
//            headers.put("Host","www.yourdomain.com");
//            headers.put("Accept-Charset","ISO-8859-1,utf-8;q=0.7,*;q=0.7");
//            headers.put("Referer", "http://www.yourdomian.com/xxxAction.html");


            httpRequest.setHeaders(headers.toArray(new Header[]{}));


            if (requestInfo.getParams() != null) {
                //设置参数
                List<NameValuePair> nvps = new ArrayList<NameValuePair>();
                for (Map.Entry<String, String> entry : requestInfo.getParams().entrySet()) {
                    nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
                }
                if (httpRequest instanceof HttpEntityEnclosingRequestBase) {
                    ((HttpEntityEnclosingRequestBase) httpRequest).setEntity(new UrlEncodedFormEntity(nvps, ENCODE));
                }
            }


            return httpRequest;
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException ("不支持的编码:" + ENCODE, e);
        }
    }

    /**
     * 处理结果信息
     *
     * @param response
     * @return
     */
    protected ResponseInfo processResponse(CloseableHttpResponse response) {

        try {
            ResponseInfo responseInfo = new ResponseInfo();

            responseInfo.setStatusCode(response.getStatusLine().getStatusCode());

            HttpEntity entity = response.getEntity();

            if (entity.getContentType() != null){
                responseInfo.setContentType(entity.getContentType().getValue());
            }

            responseInfo.setHeaders(response.getAllHeaders());
            if (entity != null) {
                responseInfo.setBody(EntityUtils.toByteArray(entity));
            }
            // 销毁
            EntityUtils.consume(entity);

            return responseInfo;
        } catch (IOException e) {
            throw new RuntimeException("获取response结果失败", e);
        } finally {
            AgentHttpUtils.closeResponse(response);
        }

    }

    public ResponseInfo postMultipart(String postUrl, RequestInfo requestInfo, String fileName,
                                      InputStream fileInputStream) {

        try {
            HttpRequestBase httpPost = buildHttpRequest(postUrl, new HttpPost(), requestInfo);

            InputStreamBody bin = new InputStreamBody(fileInputStream, fileName);
            StringBody uploadFileName = new StringBody(fileName, ContentType.create("text/plain", Consts.UTF_8));

            // 以浏览器兼容模式运行，防止文件名乱码。
            HttpEntity reqEntity = MultipartEntityBuilder.create().setMode(HttpMultipartMode.BROWSER_COMPATIBLE)
                    .addPart("file", bin).addPart("filename", uploadFileName).setCharset(Consts.UTF_8).build();

            ((HttpPost) httpPost).setEntity(reqEntity);

            // 发起请求 并返回请求的响应
            CloseableHttpResponse response = this.httpClient.execute(httpPost);

            return processResponse(response);

        } catch (IOException ex) {
            throw new RuntimeException("发起postMultipart请求失败", ex);
        }
    }

    public ResponseInfo post(String postUrl, RequestInfo requestInfo) {
        HttpRequestBase httpPost = buildHttpRequest(postUrl, new HttpPost(), requestInfo);
        try {
            CloseableHttpResponse response = this.httpClient.execute(httpPost);
            return processResponse(response);
        } catch (IOException e) {
            throw new RuntimeException("发起post请求失败", e);
        }
    }

    public ResponseInfo get(String getUrl, RequestInfo requestInfo) {
        try {
            HttpRequestBase httpGet = buildHttpRequest(getUrl, new HttpGet(), requestInfo);
            CloseableHttpResponse response = this.httpClient.execute(httpGet);
            return processResponse(response);
        } catch (IOException e) {
            throw new RuntimeException("发起get请求失败", e);
        }

    }

}
